﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using SLASCIICore;
using System.Windows.Resources;

namespace JetLag2011
{
    public partial class MainPage : UserControl
    {
        SoundEffectsManager sfxManager = new SoundEffectsManager();
        MusicManager musicManager = new MusicManager();
        private ASCIIRenderer renderer = new ASCIIRenderer();
        int lives;
        int score;
        int position;
        int delta;
        int bombs;
        int level;
        int levelCounter;
        int shields;
        int invincibility;
        int multiplier;
        int divisor;
        int speed;
        bool reverseKeys;
        CellColor[] walls = new CellColor[]
        {
            CellColor.Blue,
            CellColor.Green,
            CellColor.Cyan,
            CellColor.Red,
            CellColor.Magenta,
            CellColor.Yellow,
            CellColor.LightGray,
            CellColor.DarkGray,
            CellColor.LightBlue,
            CellColor.LightGreen,
            CellColor.LightCyan,
            CellColor.LightRed,
            CellColor.LightMagenta
        };
        Random random = new Random();
        Dictionary<LuckyCharm, byte> charmCharacters = new Dictionary<LuckyCharm, byte>();
        Dictionary<LuckyCharm, CellColor> charmColors = new Dictionary<LuckyCharm, CellColor>();
        List<LuckyCharm> generator = new List<LuckyCharm>();

        private GameState state = GameState.None;
        private GameState State
        {
            get
            {
                return state;
            }
            set
            {
                if (state != value)
                {
                    state = value;
                    if (gameStateStartHandlers.ContainsKey(State))
                    {
                        gameStateStartHandlers[State]();
                    }
                }
            }
        }
        private delegate void GameStateHandler();
        private delegate void GameStateMouseHandler(MouseButtonEventArgs args);
        private delegate void GameStateKeyHandler(KeyEventArgs args);
        private Dictionary<GameState, GameStateHandler> gameStateStartHandlers = new Dictionary<GameState, GameStateHandler>();
        private Dictionary<GameState, GameStateHandler> gameStateTimerHandlers = new Dictionary<GameState, GameStateHandler>();
        private Dictionary<GameState, GameStateMouseHandler> gameStateMouseUpHandlers = new Dictionary<GameState, GameStateMouseHandler>();
        private Dictionary<GameState, GameStateKeyHandler> gameStateKeyDownHandlers = new Dictionary<GameState, GameStateKeyHandler>();

        private void SetHandlers()
        {
            SetStartHandlers();
            SetTimerHandlers();
            SetMouseUpHandlers();
            SetKeyDownHandlers();
        }

        private void SetStartHandlers()
        {
            gameStateStartHandlers.Add(GameState.Splash, SplashStartHandler);
            gameStateStartHandlers.Add(GameState.Title, TitleStartHandler);
            gameStateStartHandlers.Add(GameState.Help, HelpStartHandler);
            gameStateStartHandlers.Add(GameState.StartGame, StartGameStartHandler);
            gameStateStartHandlers.Add(GameState.StartRun, StartRunStartHandler);
            gameStateStartHandlers.Add(GameState.Run, RunStartHandler);
            gameStateStartHandlers.Add(GameState.EndRun, EndRunStartHandler);
            gameStateStartHandlers.Add(GameState.EndGame, EndGameStartHandler);
            gameStateStartHandlers.Add(GameState.About, AboutStartHandler);
            gameStateStartHandlers.Add(GameState.Options, OptionsStartHandler);
            gameStateStartHandlers.Add(GameState.TopTen, TopTenStartHandler);
        }

        private void SetTimerHandlers()
        {
            gameStateTimerHandlers.Add(GameState.Run, RunTimerHandler);
        }

        private void SetMouseUpHandlers()
        {
            gameStateMouseUpHandlers.Add(GameState.Splash, SplashMouseUpHandler);
        }

        private void SetKeyDownHandlers()
        {
            gameStateKeyDownHandlers.Add(GameState.Title, TitleKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.Help, HelpKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.StartRun, StartRunKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.Run, RunKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.EndRun, EndRunKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.EndGame, EndGameKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.About, AboutKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.Options, OptionsKeyDownHandler);
            gameStateKeyDownHandlers.Add(GameState.TopTen, TopTenKeyDownHandler);
        }

        private void DrawBox(int left, int top, int width, int height, SLASCIICore.CellColor theForegroundColor, SLASCIICore.CellColor theBackgroundColor, byte topCharacter, byte topRightCharacter, byte rightCharacter, byte bottomRightCharacter, byte bottomCharacter, byte bottomLeftCharacter, byte leftCharacter, byte topLeftCharacter)
        {
            if (width < 2) return;
            if (height < 2) return;
            renderer.SetCells(left + 1, top, width - 2, 1, topCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCell(left + width - 1, top, topRightCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCells(left + width - 1, top + 1, 1, height - 2, rightCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCell(left + width - 1, top + height - 1, bottomRightCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCells(left + 1, top + height - 1, width - 2, 1, bottomCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCell(left, top + height - 1, bottomLeftCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCells(left, top + 1, 1, height - 2, leftCharacter, true, theForegroundColor, true, theBackgroundColor, true);
            renderer.SetCell(left, top, topLeftCharacter, true, theForegroundColor, true, theBackgroundColor, true);
        }

        private void DrawDoubleBox(int left, int top, int width, int height, SLASCIICore.CellColor theForegroundColor, SLASCIICore.CellColor theBackgroundColor)
        {
            DrawBox(left, top, width, height, theForegroundColor, theBackgroundColor, 0xcd, 0xbb, 0xba, 0xbc, 0xcd, 0xc8, 0xba, 0xc9);
        }
        private void DrawSpashTitleBackground()
        {
            renderer.SetCells(0, 0, Board.Columns, Board.Rows, 2, true, SLASCIICore.CellColor.White, true, SLASCIICore.CellColor.Black, true);
            for (int column = 0; column < 40; ++column)
            {
                for (int row = 0; row < 30; ++row)
                {
                    if (((row + column) & 1) == 0)
                    {
                        renderer.SetCell(column, row, 1, true, SLASCIICore.CellColor.LightGray, true, SLASCIICore.CellColor.Black, true);
                    }
                }
            }
            renderer.SetCells(2, 12, 1, 2, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(3, 13, 4, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(6, 9, 1, 4, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(8, 9, 1, 5, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(9, 9, 4, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(9, 11, 2, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(9, 13, 4, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(14, 9, 5, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(16, 10, 1, 4, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(20, 9, 1, 5, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(21, 13, 4, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(26, 9, 1, 5, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(30, 9, 1, 5, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(27, 9, 3, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(27, 12, 3, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(32, 9, 1, 5, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(36, 11, 1, 3, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(33, 9, 4, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(35, 11, 1, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(33, 13, 3, 1, 219, true, SLASCIICore.CellColor.LightRed, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(12, 15, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(14, 16, 1, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(12, 17, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(12, 18, 1, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(12, 19, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);


            renderer.SetCells(16, 15, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(16, 16, 1, 3, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(18, 16, 1, 3, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(16, 19, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(20, 15, 2, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(21, 16, 1, 3, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(20, 19, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);

            renderer.SetCells(24, 15, 2, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(25, 16, 1, 3, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);
            renderer.SetCells(24, 19, 3, 1, 219, true, SLASCIICore.CellColor.LightBlue, true, SLASCIICore.CellColor.Black, false);

            renderer.WriteText(0, 29, " Another fine product of PlayDeez Games ", CellColor.Black, CellColor.LightGreen);
        }

        private void SplashStartHandler()
        {
            DrawSpashTitleBackground();

            renderer.SetCells(12, 23, 14, 3, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawDoubleBox(11, 22, 16, 5, CellColor.LightBlue, CellColor.LightGray);
            renderer.WriteText(13, 24, "Click   Here", CellColor.LightMagenta, CellColor.Black);
            renderer.Render();
            musicManager.Play(Music.LeadIn);
        }

        private void SplashMouseUpHandler(MouseButtonEventArgs args)
        {
            State = GameState.Title;
        }

        private void TitleStartHandler()
        {
            DrawSpashTitleBackground();

            renderer.WriteText(12, 22, "<F1> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(17, 22, "Help Screen", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(12, 23, "<F2> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(17, 23, "New Game   ", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(12, 24, "<F3> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(17, 24, "Top Ten    ", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(12, 25, "<F4> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(17, 25, "Options    ", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(12, 26, "<F5> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(17, 26, "About      ", CellColor.LightCyan, CellColor.Black);
            renderer.Render();
        }

        private void TitleKeyDownHandler(KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.F1:
                    State = GameState.Help;
                    return;
                case Key.F2:
                    State = GameState.StartGame;
                    return;
                case Key.F3:
                    State = GameState.TopTen;
                    return;
                case Key.F4:
                    State = GameState.Options;
                    return;
                case Key.F5:
                    State = GameState.About;
                    return;
            }
        }

        private void HelpStartHandler()
        {
            renderer.SetCells(0, 0, 40, 30, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawDoubleBox(0, 0, 40, 30, CellColor.LightBlue, CellColor.DarkGray);
            renderer.WriteText(18, 1, "Help", CellColor.LightGreen, CellColor.Black);
            renderer.WriteText(12, 28, "<ESC> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(18, 28, "to go back", CellColor.LightCyan, CellColor.Black);

            renderer.SetCell(1, 2, 219, CellColor.White);
            renderer.SetCell(3, 2, 219, CellColor.Blue);
            renderer.WriteText(2, 2, "/", CellColor.LightGray,CellColor.Black);
            renderer.WriteText(5, 2, "avoid", CellColor.LightGray, CellColor.Black);
            int index = 3;
            foreach (var charm in charmCharacters.Keys)
            {
                renderer.SetCell(1, index, charmCharacters[charm], charmColors[charm]);
                index++;
            }
            renderer.WriteText(3, 3, "+5 points", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 4, "+10 points", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 5, "+20 points", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 6, "+50 points", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 7, "+100 points", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 8, "speed up*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 9, "slow down*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 10, "go left", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 11, "go right", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 12, "straighten", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 13, "+1 life", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 14, "+1 bomb*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 15, "invincibility*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 16, "+2 shield*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 17, "turns blocks to diamonds", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 18, "widens channel", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 19, "reverses left and right keys*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 20, "ends all temporary(*) effects", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 21, "destroys all blocks on screen", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 22, "centers avatar + invincibility", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 23, "score x1/4*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 24, "score x1/2*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 25, "score x1", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 26, "score x2*", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(3, 27, "score x4*", CellColor.LightGray, CellColor.Black);

            renderer.WriteText(20, 2, "<LEFT>", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(27, 2, "go left", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(20, 3, "<RIGHT>", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(28, 3, "go right", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(20, 4, "<CTRL>", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(27, 4, "use bomb", CellColor.LightCyan, CellColor.Black);

            renderer.Render();
        }

        private void HelpKeyDownHandler(KeyEventArgs args)
        {
            if (args.Key == Key.Escape)
            {
                State = GameState.Title;
            }
        }

        private void TopTenStartHandler()
        {
            renderer.SetCells(0, 0, 40, 30, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawDoubleBox(0, 0, 40, 30, CellColor.LightBlue, CellColor.DarkGray);
            renderer.WriteText(16, 1, "Top  Ten", CellColor.LightGreen, CellColor.Black);
            renderer.SetCell(0, 2, 0xCC, CellColor.LightBlue, CellColor.DarkGray);
            renderer.SetCell(39, 2, 0xb9, CellColor.LightBlue, CellColor.DarkGray);
            renderer.SetCells(1, 2, 38, 1, 0xCD, CellColor.LightBlue, CellColor.DarkGray);
            for (int row = 0; row < TopTenManager.TopTen.Count; ++row)
            {
                renderer.SetCell(0, 4 + row * 2, 0xCC, CellColor.LightBlue, CellColor.DarkGray);
                renderer.SetCell(39, 4 + row * 2, 0xb9, CellColor.LightBlue, CellColor.DarkGray);
                renderer.SetCells(1, 4 + row * 2, 38, 1, 0xCD, CellColor.LightBlue, CellColor.DarkGray);
                renderer.WriteText(1, 3 + row*2, string.Format("#{0,2} {1,-16}{2,18}",row+1,TopTenManager.TopTen[row].Name,TopTenManager.TopTen[row].Score), (TopTenManager.TopTen[row].Marked)?(CellColor.LightYellow):(CellColor.LightGray), CellColor.Black);
            }
            renderer.WriteText(14, 28, "<ESC> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(20, 28, "to exit", CellColor.LightCyan, CellColor.Black);
            renderer.Render();
        }

        private void TopTenKeyDownHandler(KeyEventArgs args)
        {
            if (args.Key == Key.Escape)
            {
                State = GameState.Title;
            }
        }


        private void OptionsStartHandler()
        {
            renderer.SetCells(0, 0, 40, 30, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawDoubleBox(0, 0, 40, 30, CellColor.LightBlue, CellColor.DarkGray);
            renderer.WriteText(16, 1, "Options", CellColor.LightGreen, CellColor.Black);
            renderer.WriteText(12, 28, "<ESC> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(18, 28, "to go back", CellColor.LightCyan, CellColor.Black);
            renderer.Render();
        }

        private void OptionsKeyDownHandler(KeyEventArgs args)
        {
            if (args.Key == Key.Escape)
            {
                State = GameState.Title;
            }
        }

        private void AboutStartHandler()
        {
            renderer.SetCells(0, 0, 40, 30, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawDoubleBox(0, 0, 40, 30, CellColor.LightBlue, CellColor.DarkGray);
            renderer.WriteText(18, 1, "About", CellColor.LightGreen, CellColor.Black);
            renderer.WriteText(1, 3,  "Developed by PlayDeezGames", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 4,  "http://www.playdeez.com", CellColor.LightBlue, CellColor.Black);
            renderer.WriteText(1, 6,  "Dedicated to my daughter Gwen, and to", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 7,  "the Lord Jesus Christ", CellColor.LightGray, CellColor.Black);

            renderer.WriteText(1, 23, "For God so loved the world that he ", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 24, "gave his one and only Son, that ", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 25, "whoever believes in him shall not ", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 26, "perish but have eternal life.", CellColor.LightGray, CellColor.Black);
            renderer.WriteText(1, 27, "John 3:16", CellColor.LightCyan, CellColor.Black);

            renderer.WriteText(12, 28, "<ESC> ", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(18, 28, "to go back", CellColor.LightCyan, CellColor.Black);
            renderer.Render();
        }

        private void AboutKeyDownHandler(KeyEventArgs args)
        {
            if (args.Key == Key.Escape)
            {
                State = GameState.Title;
            }
        }

        private void StartGameStartHandler()
        {
            lives = 3;
            score = 0;
            level = 0;
            multiplier = 1;
            divisor = 1;
            levelCounter = 0;
            State = GameState.StartRun;
        }

        private void DrawHeader()
        {
            renderer.SetCells(0, 0, 40, 1, 0, true, CellColor.Black, true, CellColor.Yellow, true);
            renderer.SetCell(0, 0, 2, true, CellColor.Black, false, CellColor.Black, false);
            renderer.WriteText(1, 0, string.Format("x{0}{1}", lives / 10, lives % 10), CellColor.Black, CellColor.Yellow);
            renderer.SetCell(5, 0, 15, true, CellColor.Black, false, CellColor.Black, false);
            renderer.WriteText(6, 0, string.Format("x{0}{1}", bombs / 10, bombs % 10), CellColor.Black, CellColor.Yellow);
            renderer.SetCell(10, 0, 0xe9, true, CellColor.Black, false, CellColor.Black, false);
            renderer.WriteText(11, 0, string.Format("x{0}{1}", shields / 10, shields % 10), CellColor.Black, CellColor.Yellow);
            renderer.SetCell(15, 0, 3, true, CellColor.Black, false, CellColor.Black, false);
            renderer.WriteText(16, 0, string.Format("x{0}{1}", invincibility / 10, invincibility % 10), CellColor.Black, CellColor.Yellow);
            renderer.WriteText(20, 0, string.Format("Scorex{0}", multiplier), CellColor.Black, CellColor.Yellow);
            if (divisor != 1)
            {
                renderer.WriteText(27, 0, string.Format("/{0}", divisor), CellColor.Black, CellColor.Yellow);
            }
            string scoreString = score.ToString();
            renderer.WriteText(40 - scoreString.Length, 0, scoreString, CellColor.Black, CellColor.Yellow);

        }

        private void StartRunStartHandler()
        {
            bombs = 3;
            position = 20;
            delta = 0;
            multiplier = 1;
            divisor = 1;
            invincibility = 0;
            speed = 0;
            shields = 0;
            reverseKeys = false;
            renderer.SetCells(0, 0, 40, 30, 0, true, CellColor.Black, true, CellColor.Black, true);
            DrawHeader();
            renderer.SetCells(level, 1, 1, 39, 219, true, walls[level], true, CellColor.Black, false);
            renderer.SetCells(39 - level, 1, 1, 39, 219, true, walls[level], true, CellColor.Black, false);
            renderer.SetCell(position, 6, 2, true, CellColor.White, true, CellColor.Black, true);
            renderer.WriteText(12, 5, "<SPACE>", CellColor.LightMagenta, CellColor.Black);
            renderer.WriteText(19, 5, " to start", CellColor.LightCyan, CellColor.Black);
            renderer.Render();
        }

        private void RunStartHandler()
        {
            StartTimer();
        }

        private void DrawWalls()
        {
            renderer.SetCell(level, 29, 219, walls[level], CellColor.Black);
            renderer.SetCell(39 - level, 29, 219, walls[level], CellColor.Black);
        }

        private void AddScore(int addition)
        {
            score += addition * multiplier / divisor;
        }

        private void Bonus()
        {
            for (int column = 0; column < 40; ++column)
            {
                for (int row = 1; row < 29; ++row)
                {
                    if (renderer.GetCellCharacter(column,row) == 219 && renderer.GetCellForegroundColor(column,row) == CellColor.White)
                    {
                        renderer.SetCell(column, row, 4, CellColor.LightYellow);
                    }
                }
            }
        }

        private void DetonateBomb()
        {
            for (int column = 0; column < 40; ++column)
            {
                for (int row = 1; row < 29; ++row)
                {
                    if (renderer.GetCellCharacter(column, row) == 219 && renderer.GetCellForegroundColor(column, row) == CellColor.White)
                    {
                        renderer.SetCell(column, row, 32, CellColor.Black);
                    }
                }
            }
        }

        private void RunTimerHandler()
        {
            renderer.SetCell(position, 6, 0x2a, CellColor.Red, CellColor.Black);
            for (int row = 1; row < 29; ++row)
            {
                for (int column = 0; column < 40; ++column)
                {
                    renderer.SetCell(column, row, renderer.GetCellCharacter(column,row + 1), renderer.GetCellForegroundColor(column,row + 1), renderer.GetCellBackgroundColor(column,row + 1));
                }
            }
            renderer.SetCells(0, 29, 40, 1, 32, CellColor.Black, CellColor.Black);
            DrawWalls();
            levelCounter++;
            if (levelCounter >= 256)
            {
                levelCounter = 0;
                if (level < walls.Length - 1)
                {
                    level++;
                    StartTimer();
                    DrawWalls();
                }
            }
            renderer.SetCell(random.Next(38 - 2 * level) + 1 + level, 29, 219, CellColor.White);
            if (random.Next(20) < (level+1))
            {
                LuckyCharm charm = generator[random.Next(generator.Count)];
                renderer.SetCell(random.Next(38 - 2 * level) + 1 + level, 29, charmCharacters[charm], charmColors[charm], CellColor.Black);
            }
            position += delta;
            if (invincibility > 0)
            {
                invincibility--;
            }
            byte theCharacter = renderer.GetCellCharacter(position,6);
            CellColor theColor = renderer.GetCellForegroundColor(position,6);
            switch (theCharacter)
            {
                case 15:
                    sfxManager.Play(SoundEffect.Cool);
                    bombs++;
                    break;
                case 0x13://bonus
                    sfxManager.Play(SoundEffect.WooHoo);
                    Bonus();
                    break;
                case 0x9b://cent
                    sfxManager.Play(SoundEffect.Chomp);
                    AddScore(5 * (level + 1));
                    break;
                case 0x24://dollar
                    sfxManager.Play(SoundEffect.Chomp);
                    AddScore(10 * (level + 1));
                    break;
                case 0x9c://pound
                    sfxManager.Play(SoundEffect.Chomp);
                    AddScore(20 * (level + 1));
                    break;
                case 0x9d://yen
                    sfxManager.Play(SoundEffect.Chomp);
                    AddScore(50 * (level + 1));
                    break;
                case 4://diamond
                    sfxManager.Play(SoundEffect.Chomp);
                    AddScore(100 * (level + 1));
                    break;
                case 32:
                    AddScore( 1 + level);
                    break;
                case 0xac:
                    sfxManager.Play(SoundEffect.Whoops);
                    multiplier = 1;
                    divisor = 4;
                    break;
                case 0xab:
                    sfxManager.Play(SoundEffect.Whoops);
                    multiplier = 1;
                    divisor = 2;
                    break;
                case 0x31://normal
                    sfxManager.Play(SoundEffect.Ding);
                    multiplier = 1;
                    divisor = 1;
                    break;
                case 0x32://double
                    sfxManager.Play(SoundEffect.Cool);
                    multiplier = 2;
                    divisor = 1;
                    break;
                case 0x34://quadrupal
                    sfxManager.Play(SoundEffect.WooHoo);
                    multiplier = 4;
                    divisor = 1;
                    break;
                case 0x19://faster
                    if (speed < 5)
                    {
                        sfxManager.Play(SoundEffect.SpeedUp);
                        speed++;
                        StartTimer();
                    }
                    break;
                case 0x18://slower
                    if (speed > -5)
                    {
                        sfxManager.Play(SoundEffect.SlowDown);
                        speed--;
                        StartTimer();
                    }
                    break;
                case 0x17://straight
                    sfxManager.Play(SoundEffect.Warble);
                    delta = 0;
                    break;
                case 0x1b://left
                    sfxManager.Play(SoundEffect.Warble);
                    delta = -1;
                    break;
                case 0x1a://right
                    sfxManager.Play(SoundEffect.Warble);
                    delta = 1;
                    break;
                case 3:
                    sfxManager.Play(SoundEffect.Charge);
                    invincibility = 50;
                    break;
                case 1:
                    sfxManager.Play(SoundEffect.WooHoo);
                    lives++;
                    break;
                case 0x3f://reverse
                    sfxManager.Play(SoundEffect.Whoops);
                    reverseKeys = !reverseKeys;
                    break;
                case 33:
                    sfxManager.Play(SoundEffect.Bomb);
                    DetonateBomb();
                    break;
                case 0xe9://shields
                    sfxManager.Play(SoundEffect.Cool);
                    shields++;
                    break;
                case 0xea://stop
                    sfxManager.Play(SoundEffect.Ding);
                    invincibility = 0;
                    multiplier = 1;
                    divisor = 1;
                    bombs = 3;
                    reverseKeys = false;
                    speed = 0;
                    shields = 0;
                    break;
                case 0x15://warp
                    sfxManager.Play(SoundEffect.Warble);
                    position = 20;
                    invincibility = 50;
                    delta = 0;
                    break;
                case 0x1d://widen
                    sfxManager.Play(SoundEffect.Warble);
                    if (level > 0) level--;
                    break;
                case 219:
                    if (theColor == CellColor.White)
                    {
                        if (invincibility > 0)
                        {
                            sfxManager.Play(SoundEffect.Chomp);
                            AddScore(10 * (level + 1));
                        }
                        else if (shields > 0)
                        {
                            sfxManager.Play(SoundEffect.Whoops);
                            shields--;
                        }
                        else
                        {
                            sfxManager.Play(SoundEffect.Death);
                            State = GameState.EndRun;
                            return;
                        }
                    }
                    else
                    {
                        sfxManager.Play(SoundEffect.Death);
                        State = GameState.EndRun;
                        return;
                    }
                    break;
            }
            theColor = CellColor.White;
            theCharacter = 2;
            if (shields > 0)
            {
                theColor = CellColor.LightBlue;
                theCharacter = 1;
            }
            if (invincibility > 0)
            {
                if (invincibility > 10)
                {
                    theColor = CellColor.LightCyan;
                }
                else
                {
                    if ((invincibility & 1) == 1)
                    {
                        theColor = CellColor.LightRed;
                    }
                    else
                    {
                        theColor = CellColor.LightCyan;
                    }
                }
            }
            renderer.SetCell(position, 6, theCharacter, theColor, CellColor.Black);
            DrawHeader();
            renderer.Render();
        }

        private void RunKeyDownHandler(KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.Left:
                    delta = (reverseKeys)?(1):(-1);
                    return;
                case Key.Right:
                    delta = (reverseKeys)?(-1):(1);
                    return;
                case Key.Ctrl:
                    if (bombs > 0)
                    {
                        sfxManager.Play(SoundEffect.Bomb);
                        bombs--;
                        DetonateBomb();
                    }
                    break;
            }
        }

        private void StartTimer()
        {
            StopTimer();
            timer.Interval = new TimeSpan(0, 0, 0, 0, 1000 / (10 + level + speed));
            timer.Start();
        }

        private void StopTimer()
        {
            if (timer.IsEnabled)
            {
                timer.Stop();
            }
        }

        private void StartRunKeyDownHandler(KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.Space:
                    State = GameState.Run;
                    return;
            }
        }

        private void EndRunStartHandler()
        {
            StopTimer();
            lives--;
            DrawHeader();
            renderer.SetCell(position, 6, 15, CellColor.LightRed);
            renderer.WriteText(8, 15, "Hit         to continue.", CellColor.LightCyan, CellColor.Black);
            renderer.WriteText(12, 15, "<SPACE>", CellColor.LightMagenta, CellColor.Black);
            if (lives < 1)
            {
                sfxManager.Play(SoundEffect.GameOver);
                State = GameState.EndGame;
                return;
            }
            else
            {
                renderer.WriteText(7, 14, "Ouch!  That *HAD* to hurt!", CellColor.LightCyan, CellColor.Black);
                renderer.Render();
            }
        }

        private void EndRunKeyDownHandler(KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.Space:
                    State = GameState.StartRun;
                    return;
            }
        }

        private void EndGameStartHandler()
        {
            renderer.WriteText(15, 14, "Game Over!", CellColor.LightRed, CellColor.Black);
            renderer.Render();
        }

        private void EndGameKeyDownHandler(KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.Space:
                    State = GameState.Title;
                    return;
            }
        }

        private void AddToGenerator(LuckyCharm charm, int count)
        {
            while (count > 0)
            {
                generator.Add(charm);
                count--;
            }
        }
        private void SetUpGenerator()
        {
            generator.Clear();
            AddToGenerator(LuckyCharm.Cent, 16);
            AddToGenerator(LuckyCharm.Dollar, 8);
            AddToGenerator(LuckyCharm.Pound, 4);
            AddToGenerator(LuckyCharm.Yen, 2);
            AddToGenerator(LuckyCharm.Diamond, 1);
            AddToGenerator(LuckyCharm.Faster, 16);
            AddToGenerator(LuckyCharm.Slower, 1);
            AddToGenerator(LuckyCharm.Left, 4);
            AddToGenerator(LuckyCharm.Right, 4);
            AddToGenerator(LuckyCharm.Straight, 8);
            AddToGenerator(LuckyCharm.Life, 1);
            AddToGenerator(LuckyCharm.Bomb, 4);
            AddToGenerator(LuckyCharm.Heart, 8);
            AddToGenerator(LuckyCharm.Shield, 16);
            AddToGenerator(LuckyCharm.Bonus, 2);
            AddToGenerator(LuckyCharm.Widen, 4);
            AddToGenerator(LuckyCharm.Reverse, 16);
            AddToGenerator(LuckyCharm.Stop, 8);
            AddToGenerator(LuckyCharm.Instibomb, 1);
            AddToGenerator(LuckyCharm.Warp, 2);
            AddToGenerator(LuckyCharm.QuarterScore, 16);
            AddToGenerator(LuckyCharm.HalfScore, 8);
            AddToGenerator(LuckyCharm.NormalScore, 4);
            AddToGenerator(LuckyCharm.DoubleScore, 2);
            AddToGenerator(LuckyCharm.QuadrupalScore, 1);
        }

        private void SetUpLuckyCharms()
        {
            charmCharacters.Add(LuckyCharm.Cent, 0x9b);
            charmColors.Add(LuckyCharm.Cent, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Dollar, 0x24);
            charmColors.Add(LuckyCharm.Dollar, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Pound, 0x9c);
            charmColors.Add(LuckyCharm.Pound, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Yen, 0x9d);
            charmColors.Add(LuckyCharm.Yen, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Diamond, 4);
            charmColors.Add(LuckyCharm.Diamond, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Faster, 0x19);
            charmColors.Add(LuckyCharm.Faster, CellColor.LightGreen);
            charmCharacters.Add(LuckyCharm.Slower, 0x18);
            charmColors.Add(LuckyCharm.Slower, CellColor.LightGreen);
            charmCharacters.Add(LuckyCharm.Left, 0x1b);
            charmColors.Add(LuckyCharm.Left, CellColor.LightGreen);
            charmCharacters.Add(LuckyCharm.Right, 0x1a);
            charmColors.Add(LuckyCharm.Right, CellColor.LightGreen);
            charmCharacters.Add(LuckyCharm.Straight, 0x17);
            charmColors.Add(LuckyCharm.Straight, CellColor.LightGreen);
            charmCharacters.Add(LuckyCharm.Life, 1);
            charmColors.Add(LuckyCharm.Life, CellColor.White);
            charmCharacters.Add(LuckyCharm.Bomb, 15);
            charmColors.Add(LuckyCharm.Bomb, CellColor.DarkGray);
            charmCharacters.Add(LuckyCharm.Heart, 3);
            charmColors.Add(LuckyCharm.Heart, CellColor.LightRed);
            charmCharacters.Add(LuckyCharm.Shield, 0xe9);
            charmColors.Add(LuckyCharm.Shield, CellColor.LightBlue);
            charmCharacters.Add(LuckyCharm.Bonus, 0x13);
            charmColors.Add(LuckyCharm.Bonus, CellColor.LightYellow);
            charmCharacters.Add(LuckyCharm.Widen, 0x1d);
            charmColors.Add(LuckyCharm.Widen, CellColor.Magenta);
            charmCharacters.Add(LuckyCharm.Reverse, 0x3f);
            charmColors.Add(LuckyCharm.Reverse, CellColor.Magenta);
            charmCharacters.Add(LuckyCharm.Stop, 0xea);
            charmColors.Add(LuckyCharm.Stop, CellColor.Cyan);
            charmCharacters.Add(LuckyCharm.Instibomb, 33);
            charmColors.Add(LuckyCharm.Instibomb, CellColor.LightRed);
            charmCharacters.Add(LuckyCharm.Warp, 0x15);
            charmColors.Add(LuckyCharm.Warp, CellColor.LightRed);
            charmCharacters.Add(LuckyCharm.QuarterScore, 0xac);
            charmColors.Add(LuckyCharm.QuarterScore, CellColor.LightCyan);
            charmCharacters.Add(LuckyCharm.HalfScore, 0xab);
            charmColors.Add(LuckyCharm.HalfScore, CellColor.LightCyan);
            charmCharacters.Add(LuckyCharm.NormalScore, 0x31);
            charmColors.Add(LuckyCharm.NormalScore, CellColor.LightCyan);
            charmCharacters.Add(LuckyCharm.DoubleScore, 0x32);
            charmColors.Add(LuckyCharm.DoubleScore, CellColor.LightCyan);
            charmCharacters.Add(LuckyCharm.QuadrupalScore, 0x34);
            charmColors.Add(LuckyCharm.QuadrupalScore, CellColor.LightCyan);
            SetUpGenerator();
        }

        public MainPage()
        {
            InitializeComponent();

            renderer.Board = Board;
            SetUpLuckyCharms();
            timer = new DispatcherTimer();
            timer.Tick += ontimer;
            SetHandlers();
            State = GameState.Splash;
        }
        #region Event Hook Up
        private DispatcherTimer timer;
        private void Board_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (gameStateMouseUpHandlers.ContainsKey(State))
            {
                gameStateMouseUpHandlers[State](e);
            }
        }
        private void Board_KeyDown(object sender, KeyEventArgs e)
        {
            if (gameStateKeyDownHandlers.ContainsKey(State))
            {
                gameStateKeyDownHandlers[State](e);
            }
        }
        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
            this.Focus();
        }
        private void ontimer(object sender, EventArgs e)
        {
            if (gameStateTimerHandlers.ContainsKey(State))
            {
                gameStateTimerHandlers[State]();
            }
        }
        #endregion

        private void Bomb_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Bomb] = BombSfx;
        }

        private void ChargeSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Charge] = ChargeSfx;
        }

        private void ChompSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Chomp] = ChompSfx;
        }

        private void CoolSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Cool] = CoolSfx;
        }

        private void DeathSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Death] = DeathSfx;
        }

        private void DingSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Ding] = DingSfx;
        }

        private void GameOverSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.GameOver] = GameOverSfx;
        }

        private void HallelujahSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Hallelujah] = HallelujahSfx;
        }

        private void LeadInMux_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            musicManager[Music.LeadIn] = LeadInMux;
        }

        private void SlowDownSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.SlowDown] = SlowDownSfx;
        }

        private void SongMux_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            musicManager[Music.Song] = SongMux;
        }

        private void SpeedUpSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.SpeedUp] = SpeedUpSfx;
        }

        private void WarbleSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Warble] = WarbleSfx;
        }

        private void WhoopsSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.Whoops] = WhoopsSfx;
        }

        private void WooHooSfx_DownloadProgressChanged(object sender, RoutedEventArgs e)
        {
            sfxManager[SoundEffect.WooHoo] = WooHooSfx;
        }
    }
}
